package com.xs.ahoi.hcxs.utils;

import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.provider.MediaStore;
import android.support.v4.content.FileProvider;
import android.util.Pair;
import com.google.common.collect.Lists;
import com.xs.ahoi.hcxs.Ahoi;
import com.xs.ahoi.hcxs.BuildConfig;
import com.xs.ahoi.hcxs.model.vo.ImportFileItemVO;
import com.xs.ahoi.hcxs.service.BookFactory;
import cpdetector.io.CodepageDetectorProxy;
import cpdetector.io.JChardetFacade;
import org.apache.commons.io.FileUtils;

import java.io.*;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * author: ahoi
 * date: 2018/6/20 12:46
 * description:
 */
public class FileUtil {

    // 获取目录下的子集文件名和文件夹名
    public static List<ImportFileItemVO> getAllFiles(String path) {

        List<File> childFiles = getChildFiles(path);
        if (ObjectUtils.isEmpty(childFiles)) {
            return Lists.newArrayList();
        }

        // 文件排前面，文件夹排后面，再按名字升序
        return childFiles.stream()
                .map(ImportFileItemVO::convertFromFile)
                .sorted((o1, o2) -> o1.getName().toLowerCase().compareTo(o2.getName().toLowerCase()))
                .sorted((o1, o2) -> o2.getFileType().getCode() - o1.getFileType().getCode())
                .collect(Collectors.toList());
    }

    public static List<File> getChildFiles(String path) {
        File baseFile = new File(path);
        if (baseFile.isFile() || !baseFile.exists()) {
            return Lists.newArrayList();
        }
        File[] files = baseFile.listFiles(RegexConstants.fileSearchFilter);
        return Arrays.asList(files);
    }

    public static String[] getAssetsFiles(String path) {
        try {
            return Ahoi.getInstance().getApplicationContext().getAssets().list(path);
        } catch (IOException e) {
            e.printStackTrace();
            LogUtil.e("路径不存在：path=" + path);
        }
        return new String[0];
    }

    public static String byteToSize(Number number, int toFix) {
        float result = number.floatValue();
        if (result < 1024) {
            return result + "B";
        }
        result /= 1024;
        if (result < 1024) {
            return ObjectUtils.toFix(result, toFix) + "K";
        }
        result /= 1024;
        return ObjectUtils.toFix(result, toFix) + "M";
    }

    public static String byteToSize(Number number) {
        return byteToSize(number, 2);
    }

    public static boolean isFile(String path) {
        File file = new File(path);
        return file.exists() && file.isFile();
    }

    public static boolean isDir(String path) {
        File file = new File(path);
        return file.exists() && file.isDirectory();
    }

    public static File getFile(String path) {
        return new File(path);
    }

    public static void delete(List<String> paths) {
        for (String path : paths) {
            delete(path);
        }
    }

    public static void delete(String path) {
        File file = getFile(path);
        if (file.exists() && file.isFile()) {
            file.delete();
        }
    }

    public static void checkAndCreateDir(String path) {
        File file = new File(path);
        if (!isFile(path) && !isDir(path)) {
            file.getParentFile().mkdirs();
        }
    }

    // 获取sd卡目录
    public static String getSdCard() {
        return Environment.getExternalStorageDirectory().getPath();
    }

    // 复制文件
    public static boolean copy(File fromFile, File toFile) {
        boolean result = false;
        FileChannel inChannel = null;
        FileChannel outChannel = null;

        try {
            if (!isFile(fromFile.getAbsolutePath())) {
                return false;
            }
            if (!isFile(toFile.getAbsolutePath())) {
                toFile.getParentFile().mkdirs();
                toFile.createNewFile();
            }

            inChannel = new FileInputStream(fromFile).getChannel();
            outChannel = new FileOutputStream(toFile).getChannel();
            inChannel.transferTo(0, inChannel.size(), outChannel);
            result = true;
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (inChannel != null) {
                    inChannel.close();
                }
                if (outChannel != null) {
                    outChannel.force(true);
                    outChannel.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return result;
    }

    // 复制文件
    public static boolean copy(String from, String to) {
        return copy(new File(from), new File(to));
    }

    // 从assets复制文件
    public static void copyFromAssets(String from, String to) {
        InputStream is = null;
        FileOutputStream fos = null;
        try {
            is = Ahoi.getInstance().getApplicationContext().getAssets().open(from);
            fos = new FileOutputStream(to);
            byte[] buffer = new byte[1024];
            int size;
            while ((size = is.read(buffer, 0, 1024)) >= 0) {
                fos.write(buffer, 0, size);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (fos != null) {
                try {
                    fos.close();
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    // 替换文件内容
    // isReplace:是否替换 false-仅计数
    // regCheck:是否使用正则
    // ignoreCheck:是否忽略大小写
    public static int replaceContent(String filePath, String oldStr, String newStr, boolean isReplace, boolean regCheck, boolean ignoreCheck) {
        int count = 0;
        File inFile = null;
        File outFile = null;
        BufferedWriter out = null;
        BufferedReader in = null;
        try {
            inFile = new File(filePath);
            in = new BufferedReader(new InputStreamReader(new FileInputStream(inFile)));

            outFile = File.createTempFile("name", ".tmp", getFileDir(filePath));
            out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile)));

            String line;
            Pattern pattern = Pattern.compile(oldStr);
            // 忽略大小写
            if (ignoreCheck) {
                pattern = Pattern.compile(oldStr, Pattern.CASE_INSENSITIVE);
            }
            while ((line = in.readLine()) != null) {
                if (!Constants.canReplace) {
                    break;
                }

                if (regCheck) {
                    if (StringUtils.regMatch(pattern, line)) {
                        if (ignoreCheck) {
                            line = replace(true, line, "(?i)" + oldStr, newStr, count);
                        } else {
                            line = replace(true, line, oldStr, newStr, count);
                        }
                        count++;
                    }
                } else {
                    if (ignoreCheck) {
                        if (line.toLowerCase().contains(oldStr.toLowerCase())) {
                            line = replace(true, line, "(?i)" + oldStr, newStr, count);
                            count++;
                        }
                    } else {
                        if (line.contains(oldStr)) {
                            line = replace(false, line, oldStr, newStr, count);
                            count++;
                        }
                    }
                }
                out.write(line);
                out.newLine();
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (out != null) {
                    out.flush();
                    out.close();
                }
                if (in != null) {
                    in.close();
                }
                if (Constants.canReplace && isReplace) {
                    // 把临时文件改名为原文件名
                    outFile.renameTo(inFile);
                } else {
                    // 删除临时文件
                    outFile.delete();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return count;
    }

    private static String replace(boolean isAll, String line, String oldStr, String newStr, int count) {
        if (StringUtils.isNotEmpty(newStr) && newStr.contains(Constants.REPLACE_INDEX)) {
            newStr = newStr.replace(Constants.REPLACE_INDEX, String.valueOf(count + 1));
        }
        if (isAll) {
            return line.replaceAll(oldStr, newStr);
        }
        return line.replace(oldStr, newStr);
    }

    // 获取文件夹的路径
    private static File getFileDir(String filePath) {
        File file = new File(filePath);
        if (file.isDirectory()) {
            return file;
        }
        return file.getParentFile();
    }

    // 获取文件行数
    public static int countLines(String filePath) throws Exception {
        LineNumberReader lineNumberReader = new LineNumberReader(new FileReader(filePath));
        lineNumberReader.skip(Long.MAX_VALUE);
        int lineNumber = lineNumberReader.getLineNumber() + 1;
        lineNumberReader.close();
        return lineNumber;
    }

    // 获取文件编码
    public static String getCharset(String filePath) {
        String fileCharacterEnding = Constants.DEFAULT_CHARSET;
        CodepageDetectorProxy detector = CodepageDetectorProxy.getInstance();
        detector.add(JChardetFacade.getInstance());
        Charset charset = null;
        try {
            File file = new File(filePath);
            charset = detector.detectCodepage(file.toURL());
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (charset != null) {
            fileCharacterEnding = charset.name();
        }

        return fileCharacterEnding;
    }

    // 文件转码为UTF8：使用文件原本编码读取数据，然后用UTF-8写入数据
    public static boolean convertToUTF8(String filePath) {
        File srcFile = new File(filePath);
        String srcEncoding = getCharset(filePath);
        try {
            FileUtils.writeLines(new File(filePath), Constants.DEFAULT_CHARSET, FileUtils.readLines(srcFile, srcEncoding));
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
        BookFactory.getInstance().setCharset(Constants.DEFAULT_CHARSET);
        return true;
    }

    // 进度跳转时避免指定下标的文字为乱码，获取有效的下标
    public static int getValidPosition(int position) {
        try {
            RandomAccessFile raf = BookFactory.getInstance().getRaf();
            raf.seek(position);
            if (position >= BookFactory.getInstance().getTotalLength() - 10) {
                return position;
            }
            byte[] bytes = new byte[10];
            for (int i = 0; i < bytes.length; i++) {
                bytes[i] = raf.readByte();
            }

            // 判断第一个文字是否乱码
            String s = new String(bytes).substring(0, 1);
            if (StringUtils.isErrorCode(s)) {
                return getValidPosition(++position);
            } else {
                return position;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return position;
    }

    public static Uri getFileUri(String filePath) {
        if (!isFile(filePath)) {
            return null;
        }
        Context context = Ahoi.getInstance().getApplicationContext();
        Uri uri = null;
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
            String volumeName = "external";
            String[] projection = new String[]{MediaStore.Files.FileColumns._ID};

            Cursor cursor = context.getContentResolver().query(MediaStore.Files.getContentUri(volumeName), projection,
                    MediaStore.Images.Media.DATA + "=? ", new String[]{filePath}, null);
            if (cursor != null) {
                if (cursor.moveToFirst()) {
                    int id = cursor.getInt(cursor.getColumnIndex(MediaStore.Files.FileColumns._ID));
                    uri = MediaStore.Files.getContentUri(volumeName, id);
                }
                cursor.close();
            }
        } else {
            // Android 7.0 开始不允许 file:// Uri 的方式在不同的 App 间共享文件，我们可以通过反射把该检测干掉
//            try {
//                @SuppressLint("PrivateApi")
//                Method rMethod = StrictMode.class.getDeclaredMethod("disableDeathOnFileUriExposure");
//                rMethod.invoke(null);
//            } catch (Exception e) {
//                LogUtil.e(Log.getStackTraceString(e));
//            }
//            uri = Uri.parse(filePath);

            uri = FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID + ".provider", new File(filePath));
        }
        return uri;
    }

    // 重命名
    public static Pair<Boolean, String> rename(String path, String newFilename) {
        String newPath = path.substring(0, path.lastIndexOf("/") + 1) + newFilename;
        boolean result = new File(path).renameTo(new File(newPath));
        return Pair.create(result, newPath);
    }

    public static void main(String[] args) {
    }
}
